package com.smasher.certificate.extractor

import java.security.KeyStore
import java.security.cert.X509Certificate
import java.security.interfaces.RSAPublicKey
import java.security.MessageDigest
import java.util.jar.JarFile

// 添加新的导入
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
import org.bouncycastle.asn1.ASN1InputStream
import org.bouncycastle.asn1.cms.ContentInfo

import org.bouncycastle.cert.X509CertificateHolder
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import org.bouncycastle.cms.CMSSignedData


class SignatureExtractor {


    static void extractFromJKS(String jksPath, String password, String alias) {
        def jksFile = new File(jksPath)

        if (!jksFile.exists()) {
            println "JKS文件不存在: ${jksFile.absolutePath}"
            return
        }

        try {
            // 加载JKS密钥库
            def keyStore = KeyStore.getInstance("JKS")
            def inputStream = new FileInputStream(jksFile)
            keyStore.load(inputStream, password.toCharArray())
            inputStream.close()

            // 获取证书
            def cert = keyStore.getCertificate(alias)
            if (cert == null) {
                println "在JKS中未找到别名为 '${alias}' 的证书"
                return
            }

            println "开始提取JKS签名信息: ${jksFile.name}"
            println "证书别名: ${alias}"

            // 输出证书信息
            if (cert instanceof X509Certificate) {
                outputCertificateInfo(cert)
            } else {
                println "证书类型: ${cert.getClass().name}"
                println "不支持的证书类型，无法提取详细信息"
            }
        } catch (Exception e) {
            println "处理JKS文件时出错: ${e.message}"
            e.printStackTrace()
        }
    }


    static void extractSignatureFromApk(String apkPath) {
        def apkFile = new File(apkPath)

        if (!apkFile.exists()) {
            println "APK文件不存在: ${apkFile.absolutePath}"
            return
        }

        println "开始提取APK签名信息: ${apkFile.name}"

        try {
            // 使用Java代码提取签名信息
            def jarFile = new JarFile(apkFile)
            def entries = jarFile.entries()

            while (entries.hasMoreElements()) {
                def entry = entries.nextElement()
                if (entry.name.startsWith("META-INF/") &&
                        (entry.name.endsWith(".RSA") || entry.name.endsWith(".DSA"))) {

                    println "找到签名文件: ${entry.name}"

                    // 读取签名数据
                    def baos = new ByteArrayOutputStream()
                    def buffer = new byte[1024]
                    def inputStream = jarFile.getInputStream(entry)
                    def bytesRead

                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        baos.write(buffer, 0, bytesRead)
                    }

                    def signatureData = baos.toByteArray()
                    println "签名数据长度: ${signatureData.length}"
                    inputStream.close()
                    baos.close()

                    parsePKCS7SignatureData(signatureData)


                    break
                }
            }
            jarFile.close()
        } catch (Exception e) {
            println "处理APK签名时出错: ${e.message}"
            e.printStackTrace()
        }
    }

    private static void parsePKCS7SignatureData(byte[] signatureData) {
        try {
            // Step 1: 解析为 ASN.1 ContentInfo
            ASN1InputStream asn1In = new ASN1InputStream(new ByteArrayInputStream(signatureData))
            ContentInfo contentInfo = ContentInfo.getInstance(asn1In.readObject())
            asn1In.close()

            // Step 2: 确保是 SignedData 类型
            if (!contentInfo.getContentType().equals(PKCSObjectIdentifiers.signedData)) {
                throw new IllegalArgumentException("不是 PKCS#7 SignedData 格式")
            }

            // Step 3: 解析 SignedData
            CMSSignedData signedData = new CMSSignedData(contentInfo);

            // Step 4: 获取所有证书
            def certs = signedData.getCertificates();
            def certCollection = certs.getMatches(null); // 获取所有证书

            if (certCollection.isEmpty()) {
                System.out.println("未找到任何证书！");
                return;
            }

            // Step 5: 遍历并打印每个证书（通常只有一个）
            JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter();

            int index = 1;
            for (Object certHolderObj : certCollection) {
                X509CertificateHolder certHolder = (X509CertificateHolder) certHolderObj;
                X509Certificate cert = certConverter.getCertificate(certHolder);
                System.out.println("\n=== 证书 #" + index++ + " ===");
                outputCertificateInfo(cert);
            }

            System.out.println("\n✅ 成功解析 " + certCollection.size() + " 个证书");

        } catch (Exception e) {
            println "解析 PKCS#7 数据时出错: ${e.message}"
        }
    }

    // 输出证书信息
    private static void outputCertificateInfo(cert) {
        try {
            // 输出证书信息
            println "\n=== 证书信息 ==="
            println "证书版本: ${cert.getVersion()}"
            println "主题 (Subject): " + cert.getSubjectX500Principal().getName()
            println "发行者 (Issuer): " + cert.getIssuerX500Principal().getName()
            println "序列号: ${cert.getSerialNumber().toString(16)}"
            println "颁发者: ${cert.getIssuerDN()}"
            println "持有者: ${cert.getSubjectDN()}"
            println "有效期从: ${cert.getNotBefore()}"
            println "有效期至: ${cert.getNotAfter()}"
            println "签名算法: ${cert.getSigAlgName()}"

            // 获取公钥
            def publicKey = cert.getPublicKey()
            println "\n=== 公钥信息 ==="
            println "公钥算法: ${publicKey.getAlgorithm()}"
            println "公钥格式: ${publicKey.getFormat()}"

            // 如果是RSA公钥，提取模数
            if (publicKey instanceof RSAPublicKey) {
                def rsaPublicKey = publicKey as RSAPublicKey
                def modulus = rsaPublicKey.getModulus()

                println "密钥大小: ${rsaPublicKey.getModulus().bitLength()} 位"
                println "\n=== RSA模数 ==="
                println "十六进制:"
                println modulus.toString(16)

                println "\n十进制:"
                println modulus.toString()

                // 格式化输出模数
                def modulusHex = modulus.toString(16)
                println "\n格式化十六进制 (每行65字符):"
                println wrapString(modulusHex, 65)
            }

            // 输出Base64编码的公钥
            def publicKeyBase64 = Base64.encoder.encodeToString(publicKey.getEncoded())
            println "\n=== Base64编码的公钥 ==="
            println wrapString(publicKeyBase64, 65)

            // 计算指纹
            println "\n=== 指纹信息 ==="

            String sha256Fingerprint = calculateFingerprint(cert.getEncoded(), "SHA-256");
            String sha1Fingerprint = calculateFingerprint(cert.getEncoded(), "SHA-1");
            String md5Fingerprint = calculateFingerprint(cert.getEncoded(), "MD5");

            System.out.println("指纹 SHA-256: " + sha256Fingerprint);
            System.out.println("指纹 SHA-1:   " + sha1Fingerprint);
            System.out.println("指纹 MD5:     " + md5Fingerprint);

//            def md5 = MessageDigest.getInstance("MD5")
//            def md5Digest = md5.digest(cert.getEncoded())
//            println "MD5: ${bytesToHex(md5Digest, ":")}"
//
//            def sha1 = MessageDigest.getInstance("SHA1")
//            def sha1Digest = sha1.digest(cert.getEncoded())
//            println "SHA1: ${bytesToHex(sha1Digest, ":")}"
//
//            def sha256 = MessageDigest.getInstance("SHA256")
//            def sha256Digest = sha256.digest(cert.getEncoded())
//            println "SHA256: ${bytesToHex(sha256Digest, ":")}"
        } catch (Exception e) {
            println "输出证书信息时出错: ${e.message}"
            e.printStackTrace()
        }
    }

    // 辅助方法：字符串换行
    private static String wrapString(String str, int maxWidth) {
        def wrapped = new StringBuilder()
        for (int i = 0; i < str.length(); i += maxWidth) {
            if (wrapped.length() > 0) wrapped.append("\n")
            def endIndex = Math.min(i + maxWidth, str.length())
            wrapped.append(str.substring(i, endIndex))
        }
        return wrapped.toString()
    }

    // 辅助方法：字节数组转十六进制
    private static String bytesToHex(byte[] bytes, String separator) {
        def result = new StringBuilder()
        for (int i = 0; i < bytes.length; i++) {
            if (i > 0) result.append(separator)
            result.append(String.format("%02X", bytes[i]))
        }
        return result.toString()
    }


    private static String calculateFingerprint(byte[] data, String algorithm) {
        MessageDigest md = MessageDigest.getInstance(algorithm)
        byte[] digest = md.digest(data)
        return digest.collect { String.format("%02X", it) }.join(":")
    }

}
